﻿namespace Lilium.CSharp.Expressions

open System.Linq.Expressions
open System.Reflection

open Lilium.CSharp.Expressions.Substitutions

// Expression transformers
module Transformers =

    open System
    open Lilium.CSharp.Expressions.Substitutions.Patterns
    open Lilium.CSharp.Expressions.Substitutions.Providers

    //TODO: тут имеет смысл отказаться от списка провайдеров, потому что в Providers будет реализована 
    // композиция провайдеров
    let rec private transform (subs : SubstitutionProvider list) (expr : Expression) : Expression = 

        let transformer = { 
            new ExpressionVisitor() with
                member this.VisitMethodCall node =
                    match node with 
                    | CallSubstitution subs (meth, obj, args, sub) 
                        ->  sub.GetExpression 
                                (transform subs)
                                (Expression.Constant meth)
                                args
                                [for typeArg in  meth.GetGenericArguments() -> Expression.Constant(typeArg)]
                    | _ ->  base.VisitMethodCall node }

        transformer.Visit expr

    // Default transformation using reflected substitutions
    let Transform (expr : 'a Expression) : 'a Expression = transform [reflectedSubstitutions] expr :?> 'a Expression